package it.sportingnola.siglecartoni;

import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;

public class CartoniActivity extends ListActivity {
    protected class InitTask extends AsyncTask<Context, Integer, String> {
	// Faccio partire un task in background, mentre all'utente appare l'interfaccia di
	// Loading...
	@Override
	protected String doInBackground(Context... params) {
	    Random r=new Random();
	    if (initialize(r.nextInt(ONLINE_LIST_URL.length), true) != 0) {
		createList();
	    }
	    return "FATTO!";
	}

	@Override
	protected void onCancelled() {
	    progDailog.dismiss();
	    super.onCancelled();
	}

	@Override
	protected void onPostExecute(String result) {
	    super.onPostExecute(result);
	    progDailog.dismiss();
	    buildList(globalList);
	}

	@Override
	protected void onPreExecute() {
	    setProgressBarIndeterminateVisibility(true);
	}

	@Override
	protected void onProgressUpdate(Integer... values) {
	    super.onProgressUpdate(values);
	}
    }

    private static final int PLAY_ID=10;
    private static final int WIKI_ID=11;
    private static final int SHARE_ID=12;
    private static final int SEGNALA_ID=0;
    private static final int ABOUT_ID=1;
    private static final int VOTE_ID=2;
    private static final int SEARCH_ID=4;
    private static final String[] ONLINE_LIST_URL={"http://www.sportingnola.it/android/cartoni/l.xml",
	"http://dl.dropbox.com/u/67365005/cartoni/l.xml" };
    private static final String YT_URL="http://www.youtube.com/watch?v=";
    private static final String WIKI_B_URL="http://it.wikipedia.org/wiki/";
    private static final String TAG_NAME="sigla";
    private static final String TITLE_ATTR="t";
    private static final String YT_ATTR="v";
    private static final String WIKI_ATTR="w";
    private static final String GLOBALLIST_LABEL="globalList";
    private static final String SEARCHLIST_LABEL="searchList";
    private static final String ONSEARCH_LABEL="onSearch";
    private static final String MARKET_URL="market://details?id=it.sportingnola.siglecartoni";
    private static final String WEB_URL="http://goo.gl/qk3iC";

    private boolean onSearchFlag=false;
    private static final String MY_AD_UNIT_ID="a14f2ff7ae8abc7";
    private Document doc;
    private List<Sigla> globalList=new ArrayList<Sigla>();
    private List<Sigla> searchList=new ArrayList<Sigla>();
    private ProgressDialog progDailog;
    private ArrayAdapter<Sigla> adapter;
    protected InitTask initTask;
    private ListView list;

    /**
     * Carica la lista con le sigle
     */
    private void buildList(List<Sigla> list) {
	adapter=new CartoonAdapter(this, R.layout.sigle_row, list);
	setListAdapter(adapter);
	TextView total=(TextView) findViewById(R.id.total);
	if (onSearchFlag) {
	    total.setText("" + getText(R.string.total_search) + searchList.size());
	}
	else {
	    total.setText("" + getText(R.string.total) + globalList.size());
	}

    }

    private void createList() {
	globalList=new ArrayList<Sigla>();
	NodeList sigle=doc.getElementsByTagName(TAG_NAME);
	for (int i=0; i < sigle.getLength(); i++) {
	    Sigla s=new Sigla(((Element) sigle.item(i)).getAttribute(TITLE_ATTR),
		((Element) sigle.item(i)).getAttribute(WIKI_ATTR), ((Element) sigle.item(i)).getAttribute(YT_ATTR));
	    globalList.add(s);
	}
    }

    private void getBundle(Bundle savedInstanceState) {
	globalList=(List<Sigla>) savedInstanceState.getSerializable(GLOBALLIST_LABEL);
	searchList=(List<Sigla>) savedInstanceState.getSerializable(SEARCHLIST_LABEL);
	onSearchFlag=(Boolean) savedInstanceState.getSerializable(ONSEARCH_LABEL);
    }

    /**
     * Effettua il recupero e il parsing del file XML recuperato da remoto.
     * 
     * @param indice: l'indice nell'elenco degli url da testare
     * @param primoTentativo: se true in caso di errore richiama sé stesso con l'altro indice
     * @return numero di sigle recuperate
     */
    public int initialize(int indice, boolean primoTentativo) {
	try {
	    URL url=new URL(ONLINE_LIST_URL[indice]);
	    DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
	    DocumentBuilder db=dbf.newDocumentBuilder();
	    doc=db.parse(new InputSource(url.openStream()));
	    doc.getDocumentElement().normalize();
	    return (doc.getElementsByTagName(TAG_NAME)).getLength();
	}
	catch (Exception e) {
	    if (primoTentativo) {
		indice=indice == 0 ? 1 : 0;
		initialize(indice, false);
	    }
	}
	return 0;
    }

    private void loadList() {
	progDailog=ProgressDialog.show(this, "" + getText(R.string.loadingTitle), "" + getText(R.string.loading), true);
	progDailog.setIndeterminate(true);
	initTask=new InitTask();
	initTask.execute(this);
    }

    @Override
    public void onBackPressed() {
	if (onSearchFlag) {
	    onSearchFlag=false;
	    searchList=new ArrayList<Sigla>();
	    buildList(globalList);
	}
	else {
	    finish();
	}
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
	AdapterContextMenuInfo info=(AdapterContextMenuInfo) item.getMenuInfo();
	switch (item.getItemId()) {
	    case WIKI_ID:
		openWiki(info.position);
		return true;
	    case PLAY_ID:
		play(info.position);
		return true;
	    case SHARE_ID:
		share(info.position);
		return true;
	}
	return super.onContextItemSelected(item);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	list=getListView();
	list.setFastScrollEnabled(true);

	// Create the adView
	AdView adView=new AdView(this, AdSize.BANNER, MY_AD_UNIT_ID);
	LinearLayout layout=(LinearLayout) findViewById(R.id.ads);
	// Add the adView to it
	layout.addView(adView);
	// Initiate a generic request to load it with an ad
	adView.loadAd(new AdRequest());
	if ((savedInstanceState != null) && (savedInstanceState.getSerializable(GLOBALLIST_LABEL) != null)) {
	    getBundle(savedInstanceState);
	    if (onSearchFlag) {
		buildList(searchList);
	    }
	    else {
		buildList(globalList);
	    }
	}
	else {
	    loadList();
	}

	registerForContextMenu(getListView());
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, v, menuInfo);
	menu.add(0, PLAY_ID, 0, R.string.apri_video);
	menu.add(0, WIKI_ID, 1, R.string.vedi_wiki);
	menu.add(0, SHARE_ID, 2, R.string.condividi);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
	super.onCreateOptionsMenu(menu);
	menu.add(Menu.NONE, ABOUT_ID, Menu.NONE, R.string.menu_about);
	menu.add(Menu.NONE, SEGNALA_ID, Menu.NONE, R.string.menu_segnalazioni);
	menu.add(Menu.NONE, VOTE_ID, Menu.NONE, R.string.menu_vota);
	menu.add(Menu.NONE, SEARCH_ID, Menu.NONE, R.string.menu_cerca);
	return true;
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
	super.onListItemClick(l, v, position, id);
	play(position);
    }

    @Override
    protected void onNewIntent(Intent intent) {
	setIntent(intent);
	if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
	    try {
		// Load budle with lists
		Bundle appData=getIntent().getBundleExtra(SearchManager.APP_DATA);
		if (appData != null) {
		    String query=intent.getStringExtra(SearchManager.QUERY);
		    search(query);
		}
	    }
	    catch (Exception e) {
		buildList(globalList);
	    }
	}
	else {
	    if ((globalList == null)) {
		loadList();
	    }
	    else {
		buildList(globalList);
	    }
	}
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId()) {
	    case ABOUT_ID:
		showAbout();
		return true;
	    case SEGNALA_ID:
		showSegnalazioni();
		return true;
	    case SEARCH_ID:
		onSearchRequested();
		return true;
	    case VOTE_ID:
		Intent i=new Intent(Intent.ACTION_VIEW, Uri.parse(MARKET_URL));
		startActivity(i);
		return true;
	}
	return super.onOptionsItemSelected(item);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
	super.onRestoreInstanceState(savedInstanceState);
	getBundle(savedInstanceState);
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
	// Salva la lista letta dall'XML nel Bundle
	savedInstanceState.putSerializable(GLOBALLIST_LABEL, (Serializable) globalList);
	savedInstanceState.putSerializable(SEARCHLIST_LABEL, (Serializable) searchList);
	savedInstanceState.putSerializable(ONSEARCH_LABEL, onSearchFlag);
	super.onSaveInstanceState(savedInstanceState);
    }

    /**
     * Salvataggio della lista globale
     */
    @Override
    public boolean onSearchRequested() {
	Bundle appData=new Bundle();
	appData.putSerializable(GLOBALLIST_LABEL, (Serializable) globalList);
	startSearch(null, false, appData, false);
	return true;
    }

    /**
     * Apre un uri all'esterno
     * 
     * @param position: la posizione all'interno della lista
     */
    private void openWiki(int position) {
	List<Sigla> l=onSearchFlag ? searchList : globalList;
	String wUrl=WIKI_B_URL + string2Wiki(l.get(position));
	Uri uri=Uri.parse(wUrl);
	Intent i=new Intent(Intent.ACTION_VIEW, uri);
	startActivity(i);
    }

    /**
     * Apre un url esterno di Youtube prendendolo dalla lista corrente
     * 
     * @param position: la posizione della sigla nella lista
     */
    private void play(int position) {
	List<Sigla> l=onSearchFlag ? searchList : globalList;
	Uri uri=Uri.parse(YT_URL + l.get(position).getYoutubeURL());
	Intent i=new Intent(Intent.ACTION_VIEW, uri);
	startActivity(i);
    }

    /**
     * Funzione di ricerca: data una stringa cerca nella lista delle sigle. La funzione riempe la
     * searchList e setta a <code>true</code> il parametro onSearchFlag.
     * 
     * @param dacercare: la stringa che il titolo della sigla deve contenere
     */
    public void search(String dacercare) {
	dacercare=dacercare.trim().toUpperCase();
	searchList=new ArrayList<Sigla>();
	if ("".equals(dacercare)) {
	    Toast toast=Toast.makeText(this, getString(R.string.no_search), Toast.LENGTH_LONG);
	    toast.show();
	    return;
	}
	for (Sigla sigla : globalList) {
	    if (sigla.getTitolo().toUpperCase().contains(dacercare)) {
		searchList.add(sigla);
	    }
	}
	onSearchFlag=true;
	buildList(searchList);
    }

    /**
     * Invia un'email all'autore
     */
    private void sendMail() {
	Intent emailIntent=new Intent(android.content.Intent.ACTION_SEND);
	emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{"casillo.paolo@gmail.com" });
	emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Sigle dei Cartoni");
	startActivity(Intent.createChooser(emailIntent, getString(R.string.email_send)));
    }

    /**
     * Condivide la sigla selezionata sui servizi resi disponibili sul cellulare (Facebook, Twitter,
     * posta, bluetooth...)
     * 
     * @param position: la posizione della sigla nella lista
     */
    private void share(int position) {
	List<Sigla> l=onSearchFlag ? searchList : globalList;
	Sigla s=l.get(position);
	Intent i=new Intent(android.content.Intent.ACTION_SEND);
	i.setType("text/plain");
	i.putExtra(Intent.EXTRA_SUBJECT, s.getTitolo());
	i.putExtra(Intent.EXTRA_TEXT, "" + YT_URL + s.getYoutubeURL());
	startActivity(Intent.createChooser(i, s.getTitolo()));
    }

    /**
     * Mostra un messaggio con le inforazioni sul programma e i link per mandare un'email o visitare
     * il sito.
     */
    private void showAbout() {
	AlertDialog.Builder builder=new AlertDialog.Builder(this);
	builder.setTitle(R.string.about_title);
	builder.setCancelable(true);
	builder.setMessage(getText(R.string.infoText));
	builder.setPositiveButton(R.string.sito, new DialogInterface.OnClickListener() {
	    @Override
	    public void onClick(DialogInterface dialog, int id) {
		Intent i=new Intent(Intent.ACTION_VIEW, Uri.parse(WEB_URL));
		startActivity(i);
	    }
	});
	builder.setNeutralButton(R.string.chiudi, new DialogInterface.OnClickListener() {
	    @Override
	    public void onClick(DialogInterface dialog, int id) {
		dialog.cancel();
	    }
	});

	builder.show();
    }

    /**
     * mostra le segnalazioni
     */
    private void showSegnalazioni() {
	AlertDialog.Builder builder=new AlertDialog.Builder(this);
	builder.setMessage(R.string.txt_senglazioni);
	builder.setCancelable(true);
	builder.setTitle(R.string.segnalazioni_title);
	builder.setPositiveButton(R.string.menu_mail, new DialogInterface.OnClickListener() {
	    @Override
	    public void onClick(DialogInterface dialog, int id) {
		sendMail();
	    }
	});
	builder.setNeutralButton(R.string.chiudi, new DialogInterface.OnClickListener() {
	    @Override
	    public void onClick(DialogInterface dialog, int id) {
		dialog.cancel();
	    }
	});
	builder.create();
	builder.show();
    }

    /**
     * Data una sigla trova la voce su wikipedia. Se titolo e voce coincidono, l'url di wikipedia è
     * vuoto, quindi la funzione converte il titolo di una sigla nel titolo della voce su wikipedia
     * 
     * @param sigla: la sigla di cui trovare la voce su wiki
     * @return
     */
    private String string2Wiki(Sigla sigla) {
	String ret=sigla.getWikiUrl();
	if ((ret == null) || "".equals(ret)) {
	    ret=sigla.getTitolo().replaceAll(" ", "_");
	}
	return ret;
    }

}